package com.winning.common.tools;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.framework.FrameworkServlet;
import com.winning.common.Constans;

import flex.messaging.FlexContext;

public class XMLTool {
    private static Map<String, String> map = null;

    private static Logger LOGGER = Logger.getLogger(Constans.LOG4J_PBS_LOGGER_ID);

    //服务程序源代码跟目录
    private static String serverClassPath = "";

    /**
     * 根据xml文件地址，返回xml对象
     *
     * @param xmlFilePath XML文件地址路径
     * @return
     */
    public static Document getXMLDocument(String xmlFilePath) {
        map = new HashMap<String, String>();

        //将xds注册为namesapce的名称
        map.put("xds", "urn:hl7-org:v3");
        map.put("xsi", "urn:hl7-org:v3");

        String serverFilePath = FrameworkServlet.getServerFilePath();

        String filePath = serverFilePath + "/WEB-INF/classes/";


        //服务端发布后源代码位置跟目录
        serverClassPath = filePath;

        SAXReader saxReader = new SAXReader();

        saxReader.getDocumentFactory().setXPathNamespaceURIs(map);

        Document resultDocument = null;

        //LOGGER.info("-->模板详细位置信息："+filePath + xmlFilePath);

        try {
            resultDocument = saxReader.read(new File(filePath + xmlFilePath));
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e, e.fillInStackTrace());
        }

        return resultDocument;
    }

    /**
     * 将XML文本转换为XML对象
     *
     * @param messageXML
     * @param isNameSpace 是否需要扩展名
     * @return
     */
    public static Document getDocumentFromXMLString(String messageXML, boolean isNameSpace) {
        map = new HashMap<String, String>();

        if (isNameSpace) {
            //将xds注册为namesapce的名称
            map.put("xds", "urn:hl7-org:v3");
            map.put("xsi", "urn:hl7-org:v3");
        }

        Document messageDocument = null;
        SAXReader saxReader = new SAXReader();

        try {
            /*这些错误的发生是由于一些不可见的特殊字符的存在，而这些字符对于XMl文件来说又是非法的，所以XML解析器在解析时会发生异常，官方定义了XML的无效字符分为三段：
             * 0x00 - 0x08
             * 0x0b - 0x0c
             * 0x0e - 0x1f
             */
            messageXML = messageXML.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
            /*  实体中
             *  &lt;	<	小于
             *	&gt;	>	大于
             *	&amp;	&	和号
             *	&apos;	'	单引号
             *	&quot;	"	引号
             *
             */
            messageXML = messageXML.replaceAll("\\&", "&amp;");

            saxReader.getDocumentFactory().setXPathNamespaceURIs(map);

            messageDocument = saxReader.read(new ByteArrayInputStream(messageXML.getBytes("UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            messageXML = null;

            saxReader = null;
        }

        return messageDocument;
    }

    /**
     * 利用XPATH搜索特定节点下的特定属性值
     *
     * @param document
     * @param xPathStr
     * @return
     */
    @SuppressWarnings("unchecked")
    public static synchronized String selectAttributeValueByXPath(Document document, String xPathStr) {
        String resultStr = "";
        try {
            //根据指定的XPATH配置查询节点属性值
            List<Attribute> list = document.selectNodes(xPathStr);
            Iterator<Attribute> iter = list.iterator();

            while (iter.hasNext()) {
                Attribute attribute = (Attribute) iter.next();

                //只取XPATH指定的特定一个节点的属性值
                resultStr = attribute.getStringValue() == null ? "" : attribute.getStringValue();

                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return resultStr;
    }

    /**
     * 利用XPATH搜索特定节点下的特定属性值
     *
     * @param document
     * @param xPathStr
     * @return
     */
    @SuppressWarnings("unchecked")
    public static synchronized Attribute selectAttributeObjectByXPath(Document document, String xPathStr) {
        try {
            //根据指定的XPATH配置查询节点属性值
            List<Attribute> list = document.selectNodes(xPathStr);
            Iterator<Attribute> iter = list.iterator();

            while (iter.hasNext()) {
                Attribute attribute = (Attribute) iter.next();

                return attribute;
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e, e.fillInStackTrace());
        }

        return null;
    }

    /**
     * 利用XPATH搜索特定节下的文本值
     *
     * @param document
     * @param xPathStr
     * @return
     */
    @SuppressWarnings("unchecked")
    public static synchronized String selectElementValueByXPath(Document document, String xPathStr) {
        String resultStr = "";

        //查找节点的子节点内容
        List<Element> composites = document.selectNodes(xPathStr);

        // 用xpath查找节点book的内容
        Iterator<Element> iter = composites.iterator();

        while (iter.hasNext()) {
            Element element = (Element) iter.next();

            resultStr = element.getTextTrim();
            break;
        }

        return resultStr;
    }

    /**
     * 根据属性名称获取属性值，需要判断属性是否存在
     *
     * @param element
     * @param attributeName
     * @return
     */
    public static String getAttributeValue(Element element, String attributeName) {
        String attibuteValue = "";

        if (null != element) {
            Attribute attibute = element.attribute(attributeName);

            if (null != attibute) {
                attibuteValue = attibute.getValue();
            }
        }

        return attibuteValue;
    }

    /**
     * 在xml对象中根据xpath查找需要的element节点对象 <br/>
     * 方法名称: selectElementByXPath
     *
     * @param
     * @return Element  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-10/下午1:00:34<br/>
     */
    @SuppressWarnings("unchecked")
    public static synchronized Element selectElementObjByXPath(Document document, String xPathStr) {
        Element element = null;

        //查找节点的子节点内容
        List<Element> composites = document.selectNodes(xPathStr);

        // 用xpath查找节点book的内容
        Iterator<Element> iter = composites.iterator();

        while (iter.hasNext()) {
            element = (Element) iter.next();

            if (element != null) {
                break;
            }
        }

        return element;
    }

    public static String getServerClassPath() {
        return serverClassPath;
    }

    /**
     * 在xml根节点对象中根据xpath查找需要的attribute节点对象 内容<br/>
     * 方法名称: selectAttributeValueByRootElement
     *
     * @param
     * @return Element  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-1-6/下午1:00:34<br/>
     */
    public static synchronized String selectAttributeValueByRootElement(Element root, String xPathStr) {
        String resultStr = null;

        List<Attribute> list = root.selectNodes(xPathStr);
        Iterator<Attribute> iter = list.iterator();

        while (iter.hasNext()) {
            Attribute attribute = (Attribute) iter.next();

            //只取XPATH指定的特定一个节点的属性值
            resultStr = attribute.getStringValue() == null ? "" : attribute.getStringValue();

            break;
        }

        return resultStr;
    }

    /**
     * 在xml根节点对象中根据xpath查找需要的element节点对象内容 <br/>
     * 方法名称: selectElementValueByRootElement
     *
     * @param
     * @return Element  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-1-6/下午1:00:34<br/>
     */
    public static synchronized String selectElementValueByRootElement(Element root, String xPathStr) {
        String resultStr = "";

        //查找节点的子节点内容
        List<Element> composites = root.selectNodes(xPathStr);

        // 用xpath查找节点book的内容
        Iterator<Element> iter = composites.iterator();

        while (iter.hasNext()) {
            Element element = (Element) iter.next();

            resultStr = element.getTextTrim();
            break;
        }

        return resultStr;
    }


    /**
     * 将中间CDA 文档写入独立文件夹下，以备错误定位分析用
     *
     * @param document
     * @param cdaFile
     */
    public static void writeCDAtransitionFile(Document document, String cdaFile) {
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");// 设置XML文件的编码格式

        //服务端的绝对目录，项目根目录
        String serverFilePath = FrameworkServlet.getServerFilePath();

        String filePath = serverFilePath + "/WEB-INF/classes/";

        String direPath = filePath + "com/winning/ihe/cda/cdaFiles/";

        filePath = direPath + cdaFile + "_transition_file.xml";

        //LOGGER.info("-->CDA生成文件路径:"+filePath);

        File direFile = new File(direPath);
        //创建文件夹
        if (!direFile.exists() && !direFile.isDirectory()) {
            try {
                direFile.mkdir();
            } catch (Exception e) {
                e.printStackTrace();
                LOGGER.error(e, e.fillInStackTrace());
            }
        }

        try {
            FileOutputStream fos = new FileOutputStream(filePath);
            XMLWriter xmlWriter = new XMLWriter(fos, format);
            //XMLWriter xmlWriter = new XMLWriter(new FileWriter(filePath), format);
            String cdaStr = document.asXML();
            cdaStr = cdaStr.replace("type=", "xsi:type=");
            document = DocumentHelper.parseText(cdaStr);
            xmlWriter.write(document);
            xmlWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e, e.fillInStackTrace());
        }
    }


    /**
     * 将XML Document写入到本地文件系统
     *
     * @param document
     * @param cdaTempFilePath
     */
    public static String writeCDAToFile(Document document, String cdaFile) {
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");// 设置XML文件的编码格式

        //服务端的绝对目录，项目根目录
        String serverFilePath = FrameworkServlet.getServerFilePath();

        String filePath = serverFilePath + "/WEB-INF/classes/";

        //文件夹路径
        String direPath = filePath + "com/winning/ihe/cda/cdaFiles/";
        filePath = direPath + cdaFile + ".xml";

        File direFile = new File(direPath);
        //创建文件夹
        if (!direFile.exists() && !direFile.isDirectory()) {
            try {
                direFile.mkdir();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            FileOutputStream fos = new FileOutputStream(filePath);
//			XMLWriter xmlWriter = new XMLWriter(new FileWriter(filePath), format);
            XMLWriter xmlWriter = new XMLWriter(fos, format);
            String cdaStr = document.asXML();
            cdaStr = cdaStr.replace("type=", "xsi:type=");
            document = DocumentHelper.parseText(cdaStr);
            xmlWriter.write(document);
            xmlWriter.close();
        } catch (Exception e) {
            e.printStackTrace();

            return null;
        }
        return null;
    }


}
